package com.baizhi.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


/**
 * 声明当前类为配置类
 */
@Configuration
/**
 * 声明当前类为切面类，会自动编织类中的切面和切点
 */
@Aspect
public class CacheAspect {
    @Autowired
    private RedisTemplate redisTemplate;
   private Logger logger= LoggerFactory.getLogger(CacheAspect.class);
    /**
     * 添加缓存
     * 1.判断要得到的数据在缓存中有没有
     * 2，没有的话，查询数据查询结果放入缓存中
     * 有的话直接在缓存中取
     *
     * 环绕增强，需要放行操作，可以获取方法执行的返回值（因为要先判断，有的话直接取，没有的话还要查询取）
     */
    @Around("@annotation(com.baizhi.annotation.AddCacheAnnotation)")
    public Object addCache(ProceedingJoinPoint joinPoint)throws Throwable{
        //获取类名
        String className=joinPoint.getTarget().getClass().getName();
        logger.debug("类名："+className);
        //获取方法名加形参的值
        StringBuffer stringBuffer=new StringBuffer();
        /**
         * 根据接入点获取方法的名字
         */
        String methodName=joinPoint.getSignature().getName();
        stringBuffer.append(methodName);
        Object[] args=joinPoint.getArgs();
        for(Object arg:args){
            /**
             * 方法拼接参数
             */
            stringBuffer.append(arg);
        }
        /**
         * hashKey为方法名加参数
         */
        String hashKey=stringBuffer.toString();
        logger.debug("hashKey:"+hashKey);
        //3.判断要得到的数据在缓存中没有
        HashOperations hashOperations=redisTemplate.opsForHash();
        /**
         * result为该类中方法的返回值
         */
        Object result=hashOperations.get(className,hashKey);
        if(result==null){
            logger.debug("查询数据库");
            //4.没有的话，查询数据，查询结果放到缓存中
            //执行放行操作，查询数据库 就是被切得方法执行的返回值结果
            result = joinPoint.proceed();
            Map map=new HashMap();
            map.put(hashKey,result);
            hashOperations.putAll(className,map);
            //设值失效时间 expire参数1要设值的key 参数2 时间数 参数3 单位
            redisTemplate.expire(className,12, TimeUnit.SECONDS);
        }else{
            logger.debug("缓存取值");
        }
        return result;
    }

    /**
     * 删除缓存
     *
     * 切注解
     *
     */
    @Before("@annotation(com.baizhi.annotation.DeleteCacheAnnotation)")
    public void deletCache(JoinPoint joinPoint){
        /**
         * 执行删除缓存
         */
        //首先获取要删除缓存的类名
        String className=joinPoint.getTarget().getClass().getName();
        logger.debug("要删除的类名；"+className);
        //2.删除
        redisTemplate.delete(className);
    }
}
